/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.sys>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

 /***************************************************************************
 * Name: serializer.cpp
 *
 * Purpose: serializer implementation for 'COM' Functional
 *
 * Developer:
 *   wen.gu , 2020-07-28
 *
 * TODO:
 *
 ***************************************************************************/

 /******************************************************************************
 **    INCLUDES
 ******************************************************************************/
#include "panda/sys/serializer.h"
#include "panda/core/utils.h"

namespace panda
{
namespace sys
{
/******************************************************************************
 **    MACROS
 ******************************************************************************/
#define DEFAULT_BUF_SIZE (256)

/******************************************************************************
 **    VARIABLE DEFINITIONS
 ******************************************************************************/


 class Serializer::impl
{
public:
    using DataByteOrder = panda::core::DataByteOrder;
public:
    impl(uint32_t bufSize);
    ~impl();
    void resizeBuf(uint32_t newSize);
public:
    DataByteOrder mByteOrder = DataByteOrder::LittleEndian;
    uint8_t* mData = nullptr; /**< pointer to data buffer */
    uint32_t mPos = 0;      /**< offset position of parcel operation */
    uint32_t mSize = 0;       /**< the size of data buffer */

};
/******************************************************************************
 **    FUNCTION DEFINITIONS
 ******************************************************************************/
Serializer::impl::impl(uint32_t bufSize)
{
    mData = new uint8_t[bufSize];
    mSize = bufSize;
    mByteOrder = panda::core::GetPlatformByteOrder(); /** get the data byte order of current platform */
    mData[mPos++] = (uint8_t)mByteOrder;
}

Serializer::impl::~impl()
{
    if (mData)
    {
        delete[] mData;
    }
}



void Serializer::impl::resizeBuf(uint32_t newSize)
{
    uint8_t* oldBuf = mData;
    uint8_t* newBuf = new uint8_t[newSize];

    if (oldBuf)
    {
        if (mPos > 0)
        {
            memcpy(newBuf, oldBuf, mPos);
        }

        delete[] oldBuf;
    }


    mData = newBuf;
    mSize = newSize;
}

Serializer::Serializer()
    :mImpl(new impl(DEFAULT_BUF_SIZE))
{
    //todo something 
}

Serializer::~Serializer()
{
    //todo something 
}


/** for serialize */
void Serializer::write(bool val)
{
    write((const uint8_t*)&val, sizeof(val));
}

void Serializer::write(uint8_t val)
{
    write((const uint8_t*)&val, sizeof(val));
}

void Serializer::write(uint16_t val)
{
    write((const uint8_t*)&val, sizeof(val));
}

void Serializer::write(uint32_t val)
{
    write((const uint8_t*)&val, sizeof(val));
}

void Serializer::write(uint64_t val)
{
    write((const uint8_t*)&val, sizeof(val));
}

void Serializer::write(int8_t val)
{
    write((const uint8_t*)&val, sizeof(val));
}

void Serializer::write(int16_t val)
{
    write((const uint8_t*)&val, sizeof(val));
}

void Serializer::write(int32_t val)
{
    write((const uint8_t*)&val, sizeof(val));
}

void Serializer::write(int64_t val)
{
    write((const uint8_t*)&val, sizeof(val));
}

void Serializer::write(float val)
{/** todo refine me?? if float bit changed in diffrent platform */
    write((const uint8_t*)&val, sizeof(val));
}

void Serializer::write(double val)
{
    write((const uint8_t*)&val, sizeof(val));
}

void Serializer::write(const uint8_t* data, uint32_t size)
 {
     if ((mImpl->mPos + size) > mImpl->mSize)
     {
         uint32_t oldSize = (mImpl->mSize >= size) ? mImpl->mSize : size;
         uint32_t newSize = oldSize + (oldSize / 2);

         mImpl->resizeBuf(newSize);
     }

     memcpy(mImpl->mData + mImpl->mPos, data, size);

     mImpl->mPos += size;

 }

void Serializer::write(const std::string& val)
 {
     write((const uint8_t*)val.c_str(), uint32_t(val.size() + 1));
 }

 uint8_t* Serializer::payload()
 {
     return mImpl->mData;
 }

 uint32_t Serializer::size()
 {
     return mImpl->mPos;
 }


} /** namespace sys */
} /** namespace panda */


